<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'
import { CreateElement } from 'vue'
import { getSize, Rect } from './utils'

@Component({
  name: 'CollapseTransition',
})
export default class extends Vue {
  render(createElement: CreateElement) {
    return createElement(
      'transition',
      {
        on: {
          beforeEnter: this.beforeEnter,
          enter: this.enter,
          afterEnter: this.afterEnter,
          beforeLeave: this.beforeLeave,
          leave: this.leave,
          afterLeave: this.afterLeave,
        },
      },
      this.$slots.default,
    )
  }

  @Prop({ type: Number, default: 300 }) duration!: number

  @Prop({ type: String, default: 'ease' }) easing!: string

  private saveTransition = ''

  setTransition(el: HTMLElement) {
    this.saveTransition = el.style.transition
    el.style.transition = `
      ${this.duration}ms height ${this.easing},
      ${this.duration}ms padding-top ${this.easing},
      ${this.duration}ms padding-bottom ${this.easing}
    `
  }

  resetTransition(el: HTMLElement) {
    el.style.transition = this.saveTransition
  }

  beforeEnter(el: HTMLElement) {
    this.setTransition(el)
    el.dataset.oldPaddingTop = el.style.paddingTop
    el.dataset.oldPaddingBottom = el.style.paddingBottom

    el.style.height = '0'
    el.style.paddingTop = '0'
    el.style.paddingBottom = '0'
  }

  enter(el: HTMLElement) {
    el.dataset.oldOverflow = el.style.overflow
    const rect: Rect = getSize(el)
    // 恢复高度
    if (rect.height !== 0) {
      el.style.height = rect.height + 'px'
    } else {
      el.style.height = ''
    }
    // 恢复样式
    el.style.paddingTop = el.dataset.oldPaddingTop as string
    el.style.paddingBottom = el.dataset.oldPaddingBottom as string
    el.style.overflow = 'hide'
  }

  afterEnter(el: HTMLElement) {
    this.resetTransition(el)

    el.style.height = ''
    el.style.overflow = el.dataset.oldOverflow as string
  }

  beforeLeave(el: HTMLElement) {
    // 保存样式
    el.dataset.oldOverflow = el.style.overflow
    el.dataset.oldPaddingTop = el.style.paddingTop
    el.dataset.oldPaddingBottom = el.style.paddingBottom
    el.style.height = getSize(el).height + 'px'
  }

  leave(el: HTMLElement) {
    const rect: Rect = getSize(el)
    if (rect.height !== 0) {
      this.setTransition(el)
      el.style.height = '0'
      el.style.paddingTop = '0'
      el.style.paddingBottom = '0'
    }
  }

  afterLeave(el: HTMLElement) {
    this.resetTransition(el)

    // 恢复样式
    el.style.height = ''
    el.style.paddingTop = el.dataset.oldPaddingTop as string
    el.style.paddingBottom = el.dataset.oldPaddingBottom as string
    el.style.overflow = el.dataset.oldOverflow as string
  }
}
</script>
